﻿// Inner Fire 游戏引擎库
// LUA工具集
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 用于统一管理LUA的环境，尽量把LUA封装起来
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-03-25

#include "klua.h"
#include <game/core/timer.h>
#include <global_switch.h>
#include <klog.h>
#include <ktime.h>
#include <unit_test.h>

namespace ikit {

int lua_sprintf(lua_State* L, char* buffer, int max) {
  int nargs = lua_gettop(L);
  memset(buffer, 0, max);

  for (int i = 1; i <= nargs; ++i) {
    if (i != 1) {
      strcat(buffer, " "); // 添加参数分隔空格
    }

    switch (lua_type(L, i)) {
    case LUA_TNUMBER:
      if (lua_isinteger(L, i)) {
        sprintf(buffer + strlen(buffer), "%lld", lua_tointeger(L, i));
      } else {
        sprintf(buffer + strlen(buffer), "%.3g", lua_tonumber(L, i));
      }
      break;
    case LUA_TSTRING:
      sprintf(buffer + strlen(buffer), "%s", lua_tostring(L, i));
      break;
    case LUA_TBOOLEAN:
      sprintf(buffer + strlen(buffer), "%s",
          lua_toboolean(L, i) ? "true" : "false");
      break;
    case LUA_TNIL:
      strcat(buffer, "nil");
      break;
    case LUA_TTABLE:
      sprintf(buffer + strlen(buffer), "table(%p)", lua_topointer(L, i));
      break;
    case LUA_TFUNCTION:
      sprintf(buffer + strlen(buffer), "function(%p)", lua_topointer(L, i));
      break;
    case LUA_TUSERDATA:
      sprintf(buffer + strlen(buffer), "userdata(%p)", lua_topointer(L, i));
      break;
    default:
      sprintf(buffer + strlen(buffer), "%s(%p)", lua_typename(L, i),
          lua_topointer(L, i));
    }
  }

  return 0;
}

void lua_push_sstr(lua_State* L, ikit::sstr str) {
  lua_pushlstring(L, str.c_str(), str.size());
}

int lua_return_float2(lua_State* L, const DirectX::XMFLOAT2& p) {
  lua_pushnumber(L, (lua_Number)p.x);
  lua_pushnumber(L, (lua_Number)p.y);
  return 2;
}

int lua_return_float3(lua_State* L, const DirectX::XMFLOAT3& p) {
  lua_pushnumber(L, (lua_Number)p.x);
  lua_pushnumber(L, (lua_Number)p.y);
  lua_pushnumber(L, (lua_Number)p.z);
  return 3;
}

int lua_return_nil(lua_State* L) {
  lua_pushnil(L);
  return 1;
}

void lua_register_metatable(
    lua_State* L, const char* metatable_name, luaL_Reg* methods) {
  // 1. 创建元表并注册到Registry
  luaL_newmetatable(L, metatable_name);
  // 2. 设置__index指向自身（支持面向对象调用）
  lua_pushvalue(L, -1);
  lua_setfield(L, -2, "__index");

  // 3. 注册成员函数到元表
  luaL_setfuncs(L, methods, 0);

  // 4. 弹出元表（保留在Registry中供后续使用）
  lua_pop(L, 1);
}

void lua_register_metatable_inheritance(lua_State* L, const char* child_name,
    const char* parent_name, luaL_Reg* methods) {
  // 先获取父类元表
  luaL_getmetatable(L, parent_name);

  // 创建子类元表（继承父类）
  luaL_newmetatable(L, child_name);
  lua_pushvalue(L, -2);    // 复制父类元表到栈顶
  lua_setmetatable(L, -2); // 设置子类元表的元表为父类元表

  // 添加子类特有方法
  luaL_setfuncs(L, methods, 0);

  // 设置__index指向自身（保留父类方法查找能力）
  lua_pushvalue(L, -1);
  lua_setfield(L, -2, "__index");

  // 清理栈
  lua_pop(L, 2);

  //// 获取父类元表
  // if (luaL_getmetatable(L, parent_name) != LUA_TTABLE) {
  //   luaL_error(L, "Parent metatable '%s' not found", parent_name);
  // }

  //// 创建子类元表
  // luaL_newmetatable(L, child_name);

  //// 关键修复1：设置子类元表的元表为父类元表
  // lua_pushvalue(L, -2); // 复制父类元表
  // lua_setmetatable(L, -2);

  //// 关键修复2：设置子类__index指向父类元表（而非自身）
  // lua_pushvalue(L, -2); // 再次获取父类元表
  // lua_setfield(L, -2, "__index");

  //// 添加子类特有方法
  // luaL_setfuncs(L, methods, 0);

  //// 清理栈（父类元表+子类元表）
  // lua_pop(L, 2);
}

// 自定义输出函数
static int lua_print(lua_State* L) {
  static char buffer[1024];
  lua_sprintf(L, buffer, 1024);
  strcat(buffer, "\n");
  ikit::print_text(buffer);
  return 0;
}

LuaEnv::LuaEnv() {
  ls_ = luaL_newstate();
  luaL_openlibs(ls_);
  // 将Lua的print函数替换为自定义输出函数
  lua_register(ls_, "print", lua_print);
  // 注册系统函数
  RegisterSystemFunctions();
}

LuaEnv::~LuaEnv() { Close(); }

bool LuaEnv::Run(const char* filename) {
  char buffer[1024];
  memset(buffer, 0, sizeof(buffer));
  sprintf(buffer, "scripts/%s", filename);

  if (luaL_dofile(ls_, buffer) != LUA_OK) {
    KERROR("Error loading Lua script(%s): %s", //
        buffer, lua_tostring(ls_, -1));
    return false;
  }
  KLOG("Run '%s' success.", buffer);
  return true;
}

int LuaEnv::Reg(ikit::sstr func_name) {
  // 从注册项目中获得函数，如果没有项目，则注册一个
  int reg_id = 0;
  auto it = register_funcs_.find(func_name.uid());
  if (it == register_funcs_.end()) {
    lua_getglobal(ls_, func_name.c_str());
    if (!lua_isfunction(ls_, -1)) {
      KERROR("%s is not a function", func_name.c_str());
      lua_pop(ls_, 1);
      return 0;
    }

    // 将函数存入注册表并记录引用
    reg_id = luaL_ref(ls_, LUA_REGISTRYINDEX);
    register_funcs_[func_name.uid()] = reg_id;
  } else {
    reg_id = it->second;
  }

  // 记录此项目，用于出错
  last_func_ = func_name;

  return reg_id;
}

bool LuaEnv::Ready(int reg_id) {
  if (reg_id == 0) {
    return false;
  }
  // 从注册表获取缓存的函数
  lua_rawgeti(ls_, LUA_REGISTRYINDEX, reg_id);
  return true;
}

bool LuaEnv::CallFunc(int reg_id, int args_count, int result_count) {
  if (lua_pcall(ls_, args_count, result_count, 0) != LUA_OK) {
    KERROR("Error calling %s: %s", last_func_.c_str(), lua_tostring(ls_, -1));
    lua_pop(ls_, 1);
    return false;
  }
  return true;
}

bool LuaEnv::Call(ikit::sstr func_name, int result_count) {
  int reg_id = Reg(func_name);
  if (Ready(reg_id)) {
    return CallFunc(reg_id, 0, result_count);
  }
  return false;
}

bool LuaEnv::Call_Int(ikit::sstr func_name, int param_value, int result_count) {
  int reg_id = Reg(func_name);
  if (Ready(reg_id)) {
    lua_pushinteger(ls_, (lua_Integer)param_value);
    return CallFunc(reg_id, 1, result_count);
  }
  return false;
}

bool LuaEnv::Call_Float(
    ikit::sstr func_name, float param_value, int result_count) {
  int reg_id = Reg(func_name);
  if (Ready(reg_id)) {
    lua_pushnumber(ls_, (lua_Number)param_value);
    return CallFunc(reg_id, 1, result_count);
  }
  return false;
}

bool LuaEnv::Call_Button(ikit::sstr func_name, ikit::sstr button_id,
    int int_param, float float_param, int result_count) {
  int reg_id = Reg(func_name);
  if (Ready(reg_id)) {
    lua_pushstring(ls_, button_id.c_str());
    lua_pushinteger(ls_, (lua_Integer)int_param);
    lua_pushnumber(ls_, (lua_Number)float_param);
    return CallFunc(reg_id, 3, result_count);
  }
  return false;
}

bool LuaEnv::Call_Int2(ikit::sstr func_name, int p1, int p2, int result_count) {
  int reg_id = Reg(func_name);
  if (Ready(reg_id)) {
    lua_pushinteger(ls_, (lua_Integer)p1);
    lua_pushinteger(ls_, (lua_Integer)p2);
    return CallFunc(reg_id, 2, result_count);
  }
  return false;
}

bool LuaEnv::Call_Float2(
    ikit::sstr func_name, float p1, float p2, int result_count) {
  int reg_id = Reg(func_name);
  if (Ready(reg_id)) {
    lua_pushnumber(ls_, (lua_Number)p1);
    lua_pushnumber(ls_, (lua_Number)p2);
    return CallFunc(reg_id, 2, result_count);
  }
  return false;
}

bool LuaEnv::Call_Float3(
    ikit::sstr func_name, float p1, float p2, float p3, int result_count) {
  int reg_id = Reg(func_name);
  if (Ready(reg_id)) {
    lua_pushnumber(ls_, (lua_Number)p1);
    lua_pushnumber(ls_, (lua_Number)p2);
    lua_pushnumber(ls_, (lua_Number)p3);
    return CallFunc(reg_id, 3, result_count);
  }
  return false;
}

bool LuaEnv::Call_Float4(ikit::sstr func_name, float p1, float p2, float p3,
    float p4, int result_count) {
  int reg_id = Reg(func_name);
  if (Ready(reg_id)) {
    lua_pushnumber(ls_, (lua_Number)p1);
    lua_pushnumber(ls_, (lua_Number)p2);
    lua_pushnumber(ls_, (lua_Number)p3);
    lua_pushnumber(ls_, (lua_Number)p4);
    return CallFunc(reg_id, 4, result_count);
  }
  return false;
}

void LuaEnv::Close() {
  if (ls_) {
    lua_close(ls_);
    ls_ = nullptr;
  }
}

static int lua_get_time_millis(lua_State* L) {
  uint64_t time_ms = ikit::get_time_millis();
  lua_pushinteger(L, (lua_Integer)time_ms); // 将uint64_t转为Lua的integer类型
  return 1;
}

static int lua_get_fixed_delta_time(lua_State* L) {
  uint64_t time_ms = ikit::get_time_millis();
  lua_pushnumber(L, (lua_Number)ifire::game::g_timer.fixedDeltaTime);
  return 1;
}

static int lua_get_switch(lua_State* L) {
  const char* name = luaL_checkstring(L, 1);
  lua_pushboolean(L, ikit::get_switch(name));
  return 1;
}

static int lua_set_switch(lua_State* L) {
  const char* name = luaL_checkstring(L, 1);
  int enable = lua_toboolean(L, 2);
  ikit::set_switch(name, enable);
  return 0;
}

static int lua_get_gvalue(lua_State* L) {
  const char* name = luaL_checkstring(L, 1);
  lua_pushnumber(L, (lua_Number)ikit::get_gvalue(name));
  return 1;
}

static int lua_set_gvalue(lua_State* L) {
  const char* name = luaL_checkstring(L, 1);
  lua_Number value = lua_tonumber(L, 2);
  ikit::set_gvalue(name, static_cast<float>(value));
  return 0;
}

static int lua_call_gfunction(lua_State* L) {
  // 必须参数：name（索引1）
  ikit::sstr name(luaL_checkstring(L, 1));

  // 可选参数：pid（索引2）和 pvalue（索引3）
  lua_Integer pid = 0; // 默认值
  lua_Number pvalue = 0.0;

  int arg_count = lua_gettop(L); // 获取参数总数

  // 检查pid（索引2）是否存在且非nil
  if (arg_count >= 2 && !lua_isnil(L, 2)) {
    pid = lua_tointeger(L, 2); // 使用lua_tointeger避免类型错误
  }
  // 检查pvalue（索引3）是否存在且非nil
  if (arg_count >= 3 && !lua_isnil(L, 3)) {
    pvalue = lua_tonumber(L, 3);
  }

  float result = ikit::call_gfunction(
      name, static_cast<int>(pid), static_cast<float>(pvalue));
  lua_pushnumber(L, (lua_Number)result);
  return 1;
}

static int lua_execute_unit_test(lua_State* L) {
  const char* name = luaL_checkstring(L, 1);
  lua_Number value = lua_tonumber(L, 2);

  run_unit_test(name, static_cast<float>(value));

  return 0;
}

void LuaEnv::RegisterSystemFunctions(void) {
  auto L = ls_;

  lua_pushcfunction(L, lua_get_time_millis);
  lua_setglobal(L, "get_time_millis");

  lua_pushcfunction(L, lua_get_fixed_delta_time);
  lua_setglobal(L, "get_fixed_delta_time");

  lua_pushcfunction(L, lua_get_switch);
  lua_setglobal(L, "get_switch");

  lua_pushcfunction(L, lua_set_switch);
  lua_setglobal(L, "set_switch");

  lua_pushcfunction(L, lua_get_gvalue);
  lua_setglobal(L, "getg");

  lua_pushcfunction(L, lua_set_gvalue);
  lua_setglobal(L, "setg");

  lua_pushcfunction(L, lua_call_gfunction);
  lua_setglobal(L, "callg");

  lua_pushcfunction(L, lua_execute_unit_test);
  lua_setglobal(L, "execute_unit_test");
}

void lua_set_string(lua_State* L, const char* field, const char* string) {
  lua_pushstring(L, string);
  lua_setfield(L, -2, field);
}

void lua_set_int(lua_State* L, const char* field, int value) {
  lua_pushinteger(L, value);
  lua_setfield(L, -2, field);
}

void lua_set_float(lua_State* L, const char* field, float value) {
  lua_pushnumber(L, value);
  lua_setfield(L, -2, field);
}


} // namespace ikit